﻿using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Serialization;
using UIFrameWork;
using UnityEditor;
using UnityEngine;
public enum enResourceType
{
    BattleScene,
    Numeric,
    Sound,
    UIForm,
    UIPrefab,
    UI3DImage,
    UISprite
}
public class GameObjectPool :Singleton<GameObjectPool> {
   public class stDelayRecycle
   {
       public GameObject recycleObj;
       public int recycleTime;
       public float[] objSize;
       public Vector3[] objScale;
       public OnDelayRecycleCallBack callback;
   }
   

    public delegate void OnDelayRecycleCallBack(GameObject gameObject, float[] size, Vector3[] scale);
    private Dictionary<int ,Queue<PooledGameObjectScript>> m_pooledGameObjectsMap = new Dictionary<int, Queue<PooledGameObjectScript>>();
    private Dictionary<int,Component> m_componentMap = new Dictionary<int, Component>();
    private LinkedList<stDelayRecycle> m_delayRecycle = new LinkedList<stDelayRecycle>();
    private GameObject m_poolRoot;
    private bool m_clearPooledObjects;
    private int m_clearPooledObjectsExecuteFrame;
    private static int s_frameCounter;
    public override void Init()
    {
        this.m_poolRoot = new GameObject("GameObjectPool");
        GameObject gameObject = GameObject.Find("BootObj");
        if (gameObject != null)
        {
            this.m_poolRoot.transform.SetParent(gameObject.transform);
        }
        
    }

    public override void UnInit()
    {
    }

    public void CleearPooledObjects()
    {
        this.m_clearPooledObjects = true;
        this.m_clearPooledObjectsExecuteFrame = s_frameCounter + 1;
    }

    public void ExecuteClearPooledObjects()
    {
        for (var linknode = m_delayRecycle.First; linknode != null; linknode = linknode.Next)
        {
            if (null != linknode.Value.recycleObj)
            {
                ReCycleGameObject(linknode.Value.recycleObj);
            }
        }
        m_delayRecycle.Clear();
        this.m_componentMap.Clear();
        Dictionary<int, Queue<PooledGameObjectScript>>.Enumerator enumerator = m_pooledGameObjectsMap.GetEnumerator();
        while (enumerator.MoveNext())
        {
            KeyValuePair<int, Queue<PooledGameObjectScript>> current = enumerator.Current;
            Queue<PooledGameObjectScript> queue = current.Value;
            while (queue.Count>0)
            {
                PooledGameObjectScript pooledGameObjectScript = queue.Dequeue();
                if (null != pooledGameObjectScript && pooledGameObjectScript.gameObject != null)
                {
                    Object.Destroy(pooledGameObjectScript.gameObject);
                }
            }
        }
        m_pooledGameObjectsMap.Clear();
    }
    
    public void Update()
    {
        s_frameCounter++;
        this.UpdateDelayRecycle();
        if (this.m_clearPooledObjects && s_frameCounter == this.m_clearPooledObjectsExecuteFrame)
        {
            this.m_clearPooledObjects = false;
            this.ExecuteClearPooledObjects();
        }
    }

    public void UpdateDelayRecycle()
    {
        if (m_delayRecycle.Count <= 0)
        {
            return;
        }
        LinkedListNode<stDelayRecycle> linkedListNode = m_delayRecycle.First;
        while (linkedListNode!=null)
        {
            LinkedListNode<stDelayRecycle> linkedListNode2 = linkedListNode;
            linkedListNode = linkedListNode2.Next;
            if (null == linkedListNode2.Value.recycleObj)
            {
                this.m_delayRecycle.Remove(linkedListNode2);
            }
            else
            {
                int num = (int) Time.time * 1000;
                if (linkedListNode2.Value.recycleTime > num)
                {
                  
                        break;
                }
                if (linkedListNode2.Value.callback != null)
                {
                    linkedListNode2.Value.callback(linkedListNode2.Value.recycleObj, linkedListNode2.Value.objSize,
                        linkedListNode2.Value.objScale);
                        
                }
                this.ReCycleGameObject(linkedListNode2.Value.recycleObj);
                this.m_delayRecycle.Remove(linkedListNode2);
                
            }
        }
    }

    public GameObject GetGameObject(string prefabPath, Vector3 pos, Quaternion rot, enResourceType enResourceType)
    {
        return GetGameObject(prefabPath, pos, rot, false, enResourceType);
    }

    public GameObject GetGameObject(string prefabPath, enResourceType enResourceType)
    {
        return GetGameObject(prefabPath, Vector3.zero, Quaternion.identity, false, enResourceType);
    }

    public GameObject GetGameObject(string prefabPath, Vector3 pos, enResourceType enResourceType)
    {
        return GetGameObject(prefabPath, pos, Quaternion.identity, false, enResourceType);
    }
    private GameObject GetGameObject(string prefabPath,Vector3 pos,Quaternion rot,bool useRotation,enResourceType enResourceType )
    {
        string text = FileManager.EraseExtension(prefabPath);
        //先从缓存中取
        Queue<PooledGameObjectScript> queue = null;
        if (!this.m_pooledGameObjectsMap.TryGetValue(Utility.JavaHashCodeIgnoreCase(text), out queue))
        {
            queue = new Queue<PooledGameObjectScript>();
            this.m_pooledGameObjectsMap.Add(Utility.JavaHashCodeIgnoreCase(text),queue);
        }
        PooledGameObjectScript pooledGameObjectScript = null;
        while (queue.Count>0)
        {
            pooledGameObjectScript = queue.Dequeue();
            if (pooledGameObjectScript != null && pooledGameObjectScript.gameObject != null)
            {
                pooledGameObjectScript.gameObject.transform.SetParent(null, true);
                pooledGameObjectScript.transform.position = pos;
                pooledGameObjectScript.transform.rotation = rot;
                pooledGameObjectScript.transform.localScale = pooledGameObjectScript.m_defaultScale;
                break;
            }
        }
        if (pooledGameObjectScript == null)
        {
            //缓存中没有
            pooledGameObjectScript = CreateGameObject(prefabPath, pos, rot, useRotation, enResourceType, text);
        }
        if (pooledGameObjectScript == null)
        {
            return null;
        }
        pooledGameObjectScript.OnGet();
        return pooledGameObjectScript.gameObject;
    }

    public T GetCacheComponent<T>(GameObject go, bool isAutoAdd = false) where T:Component
    {
        if (go == null)
        {
            return null;
        }
        Component component = null;
        if (this.m_componentMap.TryGetValue(go.GetInstanceID(), out component) && component!=null)
        {
            return component as T;
        }
        component = go.GetComponent<T>();
        if (isAutoAdd && component==null)
        {
            component = go.AddComponent<T>();
        }
        if (component == null)
        {
            return null;
        }
        return component as T;
    }
    //添加的gameobject 可以从对象来获取
    public void RecycleGameObjectDelay(GameObject gameObject, int delayMillSeconds,
        OnDelayRecycleCallBack onDelayRecycleCallBack = null, float[] size = null, Vector3[] scale = null)
    {
        stDelayRecycle stDelayRecycle = new stDelayRecycle();
        stDelayRecycle.callback = onDelayRecycleCallBack;
        stDelayRecycle.objSize = size;
        stDelayRecycle.objScale = scale;
        stDelayRecycle.recycleTime = (int) (Time.time * 1000 + delayMillSeconds);
        stDelayRecycle.recycleObj = gameObject;
        if (this.m_delayRecycle.Count == 0)
        {
            this.m_delayRecycle.AddLast(stDelayRecycle);
            return;
        }
        //link 根据recycle的时间从小到大排序  循环的时候只要第一个不满足以后的 肯一定不满足
        for (var linknode = m_delayRecycle.Last; linknode != null; linknode = linknode.Previous)
        {
            if (linknode.Value.recycleTime < stDelayRecycle.recycleTime)
            {
                this.m_delayRecycle.AddAfter(linknode, stDelayRecycle);
                return;
            }
        }
        this.m_delayRecycle.AddFirst(stDelayRecycle);
        
    }

    public void ReCyclePrePareGameObject(GameObject gameObject)
    {
        ReCycleGameObject(gameObject, true);
    }
    public void ReCycleGameObject(GameObject gameObject)
    {
        this.ReCycleGameObject(gameObject,false);
    }
    private void ReCycleGameObject(GameObject gameObject,bool setInit)
    {
        if (gameObject == null)
        {
            return;
        }
        PooledGameObjectScript pooledGameObjectScript = gameObject.GetComponent<PooledGameObjectScript>();
        if (pooledGameObjectScript != null)
        {
            Queue<PooledGameObjectScript> queue = null;
            if (this.m_pooledGameObjectsMap.TryGetValue(Utility.JavaHashCodeIgnoreCase(pooledGameObjectScript.m_predagKey), out queue))
            {
                queue.Enqueue(pooledGameObjectScript);
                pooledGameObjectScript.OnRecycle();
                pooledGameObjectScript.transform.SetParent(this.m_poolRoot.transform,true);
                pooledGameObjectScript.m_isInit = setInit;
                return;
            }
        }
        Object.Destroy(pooledGameObjectScript.gameObject);
    }

    public void PrepareGameObject(string prefabPath, enResourceType enResourceType, int amount)
    {
        string text = FileManager.EraseExtension(prefabPath);
        Queue<PooledGameObjectScript> queue = null;
        if (!this.m_pooledGameObjectsMap.TryGetValue(Utility.JavaHashCodeIgnoreCase(text), out queue))
        {
            queue = new Queue<PooledGameObjectScript>();
            this.m_pooledGameObjectsMap.Add(Utility.JavaHashCodeIgnoreCase(text),queue);
        }
        if (queue.Count > amount)
        {
            return;
        }
        amount = amount - queue.Count;
        for (int i = 0; i < amount; i++)
        {
            PooledGameObjectScript pooledGameObjectScript = CreateGameObject(prefabPath, Vector3.zero,
                Quaternion.identity, false, enResourceType, text);
            if (pooledGameObjectScript!=null)
            {
                queue.Enqueue(pooledGameObjectScript);
                pooledGameObjectScript.gameObject.transform.SetParent(this.m_poolRoot.transform,true);
                pooledGameObjectScript.OnPrepare();
            }
        }
    }


    public PooledGameObjectScript CreateGameObject(string prapefabPath,Vector3 pos,Quaternion rot,bool usearotation,enResourceType enResourceType,string prefabkey)
    {
        bool needCache = enResourceType == enResourceType.BattleScene;
        // TODO 缺少资源加载模块   
        GameObject gameObject = new GameObject("");
        if (gameObject == null)
        {
            return null;
        }
        GameObject gameObject2;
        if (usearotation)
        {
            gameObject2 = Object.Instantiate(gameObject, pos, rot) as GameObject;
        }
        else
        {
            gameObject2 = Object.Instantiate(gameObject) as GameObject;
            gameObject2.transform.position = pos;
        }
        PooledGameObjectScript pooledGameObjectScript = gameObject2.GetComponent<PooledGameObjectScript>();
        if (pooledGameObjectScript == null)
        {
            pooledGameObjectScript = gameObject2.AddComponent<PooledGameObjectScript>();
        }
        pooledGameObjectScript.Initialize(prefabkey);
        pooledGameObjectScript.OnCreate();
        return pooledGameObjectScript;
    }
}







































